/***************************************************************************************
 The copyright in this software is being made available under the BSD License, included
 below. This software may be subject to other third party rights,including patent rights,
 and no such rights are granted under this license.

 Regents of the Tsinghua University, Peking University, Zhejiang University, HKUST
 Tsinghua University, Peking University, Zhejiang University, HKUST 2011

 Copyright (c) 2011, Regents of the Tsinghua University, Peking University, Zhejiang
 University, HKUST. All Rights Reserved.

 Redistribution and use in source and binary forms, with or without modification, are
 permitted provided that the following conditions are met:
   * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
   * Redistributions in binary form must reproduce the above copyright notice,
     this list of conditions and the following disclaimer in the documentation
     and/or other materials provided with the distribution.
   * Neither the names of the copyright holders nor the names of its
     contributors may be used to endorse or promote products derived from this
     software without specific prior written permission.

 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
 OF SUCH DAMAGE.
***************************************************************************************/

#include <math.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
#include <assert.h>

#include "contributors.h"
#include "global.h"
#include "vlc.h"
#include "header.h"
#include "golomb_dec.h"

extern bbv_buffer_t *pBbv;

#if TRACE
#define SYMTRACESTRING(s) strncpy(sym->tracestring,s,TRACESTRING_SIZE)
#else
#define SYMTRACESTRING(s)
#endif

extern void tracebits( const char *trace_str, int len, int info, int value1 );
extern void tracebits3( const char *trace_str, int len, int info, int value1 );

int UsedBits;

/*
*************************************************************************
* Function:ue_v, reads an ue(v) syntax element, the length in bits is stored in
the global UsedBits variable
* Input:
tracestring
the string for the trace file
bitstream
the stream to be read from
* Output:
* Return: the value of the coded syntax element
* Attention:
*************************************************************************
*/

int ue_v( char *tracestring )
{
    syntax_element_t symbol, *sym = &symbol;

    assert( currStream->stream_buffer != NULL );
    sym->type = SE_HEADER;
    sym->mapping = linfo_ue;      // Mapping rule
    SYMTRACESTRING( tracestring );
    readSyntaxElement_VLC( sym );

    return sym->value1;
}

/*
*************************************************************************
* Function:ue_v, reads an se(v) syntax element, the length in bits is stored in
the global UsedBits variable
* Input:
tracestring
the string for the trace file
bitstream
the stream to be read from
* Output:
* Return: the value of the coded syntax element
* Attention:
*************************************************************************
*/

int se_v( char *tracestring )
{
    syntax_element_t symbol, *sym = &symbol;

    assert( currStream->stream_buffer != NULL );
    sym->type = SE_HEADER;
    sym->mapping = linfo_se;      // Mapping rule: signed integer
    SYMTRACESTRING( tracestring );
    readSyntaxElement_VLC( sym );

    return sym->value1;
}

/*
*************************************************************************
* Function:ue_v, reads an u(v) syntax element, the length in bits is stored in
the global UsedBits variable
* Input:
tracestring
the string for the trace file
bitstream
the stream to be read from
* Output:
* Return: the value of the coded syntax element
* Attention:
*************************************************************************
*/

int u_v( int LenInBits, char *tracestring )
{
    syntax_element_t symbol, *sym = &symbol;

    assert( currStream->stream_buffer != NULL );
    sym->type = SE_HEADER;
    sym->mapping = linfo_ue;      // Mapping rule
    sym->len = LenInBits;
    SYMTRACESTRING( tracestring );
    readSyntaxElement_FLC( sym );

    return sym->inf;
}

int i_8( char *tracestring )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;
    syntax_element_t symbol, *sym = &symbol;
    assert( currStream->stream_buffer != NULL );

    sym->len = 8;
    sym->type = SE_HEADER;
    sym->mapping = linfo_ue;
    SYMTRACESTRING( tracestring );

    if ( ( GetBits( buf, frame_bitoffset, &( sym->inf ), BitstreamLengthInBytes, sym->len ) ) < 0 )
        return -1;
    currStream->frame_bitoffset += sym->len;
    sym->value1 = sym->inf;
    if ( sym->inf & 0x80 )
        sym->inf = -( ~( ( int )0xffffff00 | sym->inf ) + 1 );
#if TRACE
    tracebits2( sym->tracestring, sym->len, sym->inf );
#endif
    return sym->inf;
}

/*
*************************************************************************
* Function:ue_v, reads an u(1) syntax element, the length in bits is stored in
the global UsedBits variable
* Input:
tracestring
the string for the trace file
bitstream
the stream to be read from
* Output:
* Return: the value of the coded syntax element
* Attention:
*************************************************************************
*/

int u_1( char *tracestring )
{
    return u_v( 1, tracestring );
}

/*
*************************************************************************
* Function:mapping rule for ue(v) syntax elements
* Input:lenght and info
* Output:number in the code table
* Return:
* Attention:
*************************************************************************
*/

void linfo_ue( int len, int info, int *value1, int *dummy )
{
    *value1 = ( int )pow( 2, ( len / 2 ) ) + info - 1;
}

/*
*************************************************************************
* Function:mapping rule for se(v) syntax elements
* Input:lenght and info
* Output:signed mvd
* Return:
* Attention:
*************************************************************************
*/

void linfo_se( int len, int info, int *value1, int *dummy )
{
    int n;
    n = ( int )pow( 2, ( len / 2 ) ) + info - 1;
    *value1 = ( n + 1 ) / 2;
    if ( ( n & 0x01 ) == 0 )      // lsb is signed bit
        *value1 = -*value1;

}

/*
*************************************************************************
* Function:lenght and info
* Input:
* Output:cbp (intra)
* Return:
* Attention:
*************************************************************************
*/

void linfo_cbp_intra( int len, int info, int *cbp, int *dummy )
{
    extern const byte NCBP[64][2];
    int cbp_idx;
    linfo_ue( len, info, &cbp_idx, dummy );
    *cbp = NCBP[cbp_idx][0];
}

/*
*************************************************************************
* Function:
* Input:lenght and info
* Output:cbp (inter)
* Return:
* Attention:
*************************************************************************
*/

void linfo_cbp_inter( int len, int info, int *cbp, int *dummy )
{
    extern const byte NCBP[64][2];
    int cbp_idx;
    linfo_ue( len, info, &cbp_idx, dummy );
    *cbp = NCBP[cbp_idx][1];
}

/*
*************************************************************************
* Function:read next UVLC codeword from UVLC-partition and
map it to the corresponding syntax element
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int readSyntaxElement_VLC( syntax_element_t * sym )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;

    sym->len = GetVLCSymbol( buf, frame_bitoffset, &( sym->inf ), BitstreamLengthInBytes );

    if ( sym->len == -1 )
        return -1;

    currStream->frame_bitoffset += sym->len;
    sym->mapping( sym->len, sym->inf, &( sym->value1 ), &( sym->value2 ) );

#if TRACE
    tracebits( sym->tracestring, sym->len, sym->inf, sym->value1 );
#endif

    return 1;
}

//outdated fuc
int GetVLCSymbol_IntraDCMode( byte buffer[], int totbitoffset, int *info, int bytecount )
{

    register int inf;
    long byteoffset;              // byte from start of buffer
    int bitoffset;                // bit from start of byte

    int bitcounter = 1;
    int len;
    int info_bit;

    byteoffset = totbitoffset / 8;
    bitoffset = 7 - ( totbitoffset % 8 );
    //ctr_bit = (buffer[byteoffset] & (0x01 << bitoffset)); // no control bit
    //len = 1;

    ////First bit
    //if (ctr_bit)
    //{
    //  *info = 0;

    //  if (input->check_BBV_flag && pBbv)
    //  {
    //    pBbv->frame_code_bits += bitcounter;
    //  }

    //  return bitcounter;
    //}
    //else
    len = 3;

    inf = 0;
    for ( info_bit = 0; ( info_bit < ( len - 1 ) ); info_bit++ )
    {
        bitcounter++;
        bitoffset -= 1;
        if ( bitoffset < 0 )
        {
            bitoffset = bitoffset + 8;
            byteoffset++;
        }
        if ( byteoffset > bytecount )
        {
            return -1;
        }
        inf = ( inf << 1 );
        if ( buffer[byteoffset] & ( 0x01 << ( bitoffset ) ) )
            inf |= 1;
    }

    *info = inf;

    if ( input->check_BBV_flag && pBbv )
    {
        pBbv->frame_code_bits += bitcounter;
    }

    return bitcounter;            // return absolute offset in bit from start of frame
}

/*
*************************************************************************
* Function: Moves the read pointer of the partition forward by one symbol
* Input:
byte buffer[]
containing VLC-coded data bits
int totbitoffset
bit offset from start of partition
int type
expected data type (Partiotion ID)
* Output:
* Return: Length and Value of the next symbol
* Attention:As in both nal_bits.c and nal_part.c all data of one partition, slice,
picture was already read into a buffer, there is no need to read any data
here again.
\par
This function could (and should) be optimized considerably
\par
If it is ever decided to have different VLC tables for different symbol
types, then this would be the place for the implementation
\par
An alternate VLC table is implemented based on exponential Golomb codes.
The encoder must have a matching define selected.
\par
GetVLCInfo was extracted because there should be only one place in the
source code that has knowledge about symbol extraction, regardless of
the number of different NALs.
*************************************************************************
*/

int GetVLCSymbol( byte buffer[], int totbitoffset, int *info, int bytecount )
{

    register int inf;
    long byteoffset;              // byte from start of buffer
    int bitoffset;                // bit from start of byte
    int ctr_bit = 0;              // control bit for current bit posision
    int bitcounter = 1;
    int len;
    int info_bit;

    byteoffset = totbitoffset / 8;
    bitoffset = 7 - ( totbitoffset % 8 );
    ctr_bit = ( buffer[byteoffset] & ( 0x01 << bitoffset ) ); // set up control bit

    len = 1;
    while ( ctr_bit == 0 )
    {
        // find leading 1 bit
        len++;
        bitoffset -= 1;
        bitcounter++;
        if ( bitoffset < 0 )
        {
            // finish with current byte ?
            bitoffset = bitoffset + 8;
            byteoffset++;
        }
        ctr_bit = buffer[byteoffset] & ( 0x01 << ( bitoffset ) );
    }

    // make infoword
    inf = 0;                      // shortest possible code is 1, then info is always 0
    for ( info_bit = 0; ( info_bit < ( len - 1 ) ); info_bit++ )
    {
        bitcounter++;
        bitoffset -= 1;
        if ( bitoffset < 0 )
        {
            bitoffset = bitoffset + 8;
            byteoffset++;
        }
        if ( byteoffset > bytecount )
        {
            return -1;
        }
        inf = ( inf << 1 );
        if ( buffer[byteoffset] & ( 0x01 << ( bitoffset ) ) )
            inf |= 1;
    }

    *info = inf;
    if ( input->check_BBV_flag && pBbv )
    {
        pBbv->frame_code_bits += bitcounter;
    }

    return bitcounter;            // return absolute offset in bit from start of frame
}

extern void tracebits2( const char *trace_str, int len, int info );

/*
*************************************************************************
* Function:read FLC codeword from UVLC-partition
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int readSyntaxElement_FLC( syntax_element_t * sym )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;

    if ( ( GetBits( buf, frame_bitoffset, &( sym->inf ), BitstreamLengthInBytes, sym->len ) ) < 0 )
        return -1;

    currStream->frame_bitoffset += sym->len;      // move bitstream pointer
    sym->value1 = sym->inf;

#if TRACE
    tracebits2( sym->tracestring, sym->len, sym->inf );
#endif

    return 1;
}

/*
*************************************************************************
* Function:read Level VLC0 codeword from UVLC-partition
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int readSyntaxElement_Level_VLC0( syntax_element_t * sym )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;
    int len, sign, level, code;

    len = 0;

    while ( !ShowBits( buf, frame_bitoffset + len, BitstreamLengthInBytes, 1 ) )
        len++;

    len++;
    code = 1;
    frame_bitoffset += len;

    if ( len < 15 )
    {
        sign = ( len - 1 ) & 1;
        level = ( len - 1 ) / 2 + 1;
    }
    else if ( len == 15 )
    {
        // escape code
        code = ( code << 4 ) | ShowBits( buf, frame_bitoffset, BitstreamLengthInBytes, 4 );
        len += 4;
        frame_bitoffset += 4;
        sign = ( code & 1 );
        level = ( ( code >> 1 ) & 0x7 ) + 8;
    }
    else if ( len == 16 )
    {
        // escape code
        code = ( code << 12 ) | ShowBits( buf, frame_bitoffset, BitstreamLengthInBytes, 12 );
        len += 12;
        frame_bitoffset += 12;
        sign = ( code & 1 );
        level = ( ( code >> 1 ) & 0x7ff ) + 16;
    }
    else
    {
        printf( "ERROR reading Level code\n" );
        exit( -1 );
    }

    if ( sign )
        level = -level;

    sym->inf = level;
    sym->len = len;

#if TRACE
    tracebits2( sym->tracestring, sym->len, code );
#endif

    currStream->frame_bitoffset = frame_bitoffset;

    return 0;
}

/*
*************************************************************************
* Function:read Level VLC codeword from UVLC-partition
* Input:
* Output:
* Return:
* Attention:
*************************************************************************
*/

int readSyntaxElement_Level_VLCN( syntax_element_t * sym, int vlc )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;

    int levabs, sign;
    int len = 0;
    int code, sb;

    int numPrefix;
    int shift = vlc - 1;
    int escape = ( 15 << shift ) + 1;

    // read pre zeros
    numPrefix = 0;

    while ( !ShowBits( buf, frame_bitoffset + numPrefix, BitstreamLengthInBytes, 1 ) )
        numPrefix++;

    len = numPrefix + 1;
    code = 1;

    if ( numPrefix < 15 )
    {
        levabs = ( numPrefix << shift ) + 1;

        // read (vlc-1) bits -> suffix
        if ( vlc - 1 )
        {
            sb = ShowBits( buf, frame_bitoffset + len, BitstreamLengthInBytes, vlc - 1 );
            code = ( code << ( vlc - 1 ) ) | sb;
            levabs += sb;
            len += ( vlc - 1 );
        }
        // read 1 bit -> sign
        sign = ShowBits( buf, frame_bitoffset + len, BitstreamLengthInBytes, 1 );
        code = ( code << 1 ) | sign;
        len++;
    }
    else                          // escape
    {
        // read 11 bits -> levabs
        sb = ShowBits( buf, frame_bitoffset + len, BitstreamLengthInBytes, 11 );
        code = ( code << 11 ) | sb;

        levabs = sb + escape;
        len += 11;

        // read 1 bit -> sign
        sign = ShowBits( buf, frame_bitoffset + len, BitstreamLengthInBytes, 1 );
        code = ( code << 1 ) | sign;
        len++;
    }

    sym->inf = ( sign ) ? -levabs : levabs;
    sym->len = len;

    currStream->frame_bitoffset = frame_bitoffset + len;

#if TRACE
    tracebits2( sym->tracestring, sym->len, code );
#endif

    return 0;
}

/*
*************************************************************************
* Function:Reads bits from the bitstream buffer
* Input:
byte buffer[]
containing VLC-coded data bits
int totbitoffset
bit offset from start of partition
int bytecount
total bytes in bitstream
int numbits
number of bits to read
* Output:
* Return:
* Attention:
*************************************************************************
*/

int GetBits( byte buffer[], int totbitoffset, int *info, int bytecount, int numbits )
{
    register int inf;
    long byteoffset;              // byte from start of buffer
    int bitoffset;                // bit from start of byte

    int bitcounter = numbits;

    byteoffset = totbitoffset / 8;
    bitoffset = 7 - ( totbitoffset % 8 );

    inf = 0;
    while ( numbits )
    {
        inf <<= 1;
        inf |= ( buffer[byteoffset] & ( 0x01 << bitoffset ) ) >> bitoffset;
        numbits--;
        bitoffset--;
        if ( bitoffset < 0 )
        {
            byteoffset++;
            bitoffset += 8;
            if ( byteoffset > bytecount )
            {
                return -1;
            }
        }
    }

    *info = inf;

    // yin hai cang
    if ( input->check_BBV_flag && pBbv )
    {
        pBbv->frame_code_bits += bitcounter;
    }
    // yin hai cang

    return bitcounter;            // return absolute offset in bit from start of frame
}

/*
*************************************************************************
* Function:Reads bits from the bitstream buffer
* Input:
byte buffer[]
containing VLC-coded data bits
int totbitoffset
bit offset from start of partition
int bytecount
total bytes in bitstream
int numbits
number of bits to read
* Output:
* Return:
* Attention:
*************************************************************************
*/

int ShowBits( byte buffer[], int totbitoffset, int bytecount, int numbits )
{

    register int inf;
    long byteoffset;              // byte from start of buffer
    int bitoffset;                // bit from start of byte

    // yin hai cang
    if ( input->check_BBV_flag && pBbv )
    {
        pBbv->frame_code_bits += numbits;
    }
    // yin hai cang

    byteoffset = totbitoffset / 8;
    bitoffset = 7 - ( totbitoffset % 8 );

    inf = 0;
    while ( numbits )
    {
        inf <<= 1;
        inf |= ( buffer[byteoffset] & ( 0x01 << bitoffset ) ) >> bitoffset;
        numbits--;
        bitoffset--;
        if ( bitoffset < 0 )
        {
            byteoffset++;
            bitoffset += 8;
            if ( byteoffset > bytecount )
            {
                return -1;
            }
        }
    }

    return inf;                   // return absolute offset in bit from start of frame
}

int get_uv( int LenInBits, char *tracestring )
{
    syntax_element_t symbol, *sym = &symbol;

    assert( currStream->stream_buffer != NULL );
    sym->mapping = linfo_ue;      // Mapping rule
    sym->len = LenInBits;
    SYMTRACESTRING( tracestring );
    GetSyntaxElement_FLC( sym );

    return sym->inf;
}

int GetSyntaxElement_FLC( syntax_element_t * sym )
{
    int frame_bitoffset = currStream->frame_bitoffset;
    byte *buf = currStream->stream_buffer;
    int BitstreamLengthInBytes = currStream->bitstream_length;

    if ( ( GetBits( buf, frame_bitoffset, &( sym->inf ), BitstreamLengthInBytes, sym->len ) ) < 0 )
        return -1;

    sym->value1 = sym->inf;

#if TRACE
    tracebits2( sym->tracestring, sym->len, sym->inf );
#endif

    return 1;
}

/*
*************************************************************************
* Function: Check the stuffing pattern and stuffing_byte_pattern
at the end of picture header and slice
* Input:
* Output:
* Return:
* Attention:
* Author:
*************************************************************************
*/

int IsStuffingPattern( int idx, int len )
{
    int stuffing_bit_pattern;
    int stuffing_byte_pattern;
    int stuffing_byte_len;
    int is_sutffing_byte_pattern;
    unsigned int stuffing_byte_value;

    is_sutffing_byte_pattern = 1;
    stuffing_byte_value = 0;

    if ( idx == 1 )
    {
        if ( len == 0 )
        {
#if SYNTAX_REPORT
            fprintf( p_sreport, "No Stuffing Bit At The End Of Slice!\n" );
            fprintf( p_sreport, "Slice Vertical Position: %d\n\n", slice_vertical_position );
#endif
            CSyntax = 0;
            return 0;
        }
        else if ( len > 8 )
        {
#if SYNTAX_REPORT
            fprintf( p_sreport, "Invalid Stuffing Pattern at the end of slice!\n%d Stuffing Bits Found (Too Much Stuffing Bits)!\n", len );
#endif
            stuffing_bit_pattern = get_uv( len, "stuffing pattern" );
#if SYNTAX_REPORT
            fprintf( p_sreport, "Slice Vertical Position: %d\n", slice_vertical_position );
            fprintf( p_sreport, "Invalid Stuffing Pattern: 0x%X\n\n", stuffing_bit_pattern );
#endif
            CSyntax = 0;
            return 0;
        }

        stuffing_bit_pattern = get_uv( len, "stuffing pattern" );
        if ( stuffing_bit_pattern == ( 1 << ( len - 1 ) ) )
            return 1;
        else
        {
#if SYNTAX_REPORT
            fprintf( p_sreport, "Wrong Stuffing Pattern at the end of slice!\n", len );
            fprintf( p_sreport, "Slice Vertical Position: %d\n", slice_vertical_position );
            fprintf( p_sreport, "Wrong Stuffing Pattern (%d Stuffing Bits): 0x%X\n\n", len, stuffing_bit_pattern );
#endif
            CSyntax = 0;
            return 0;
        }
    }
    else
    {
        int stuffing_bit_num;
        char StartCodeType[20];

        switch ( StartCodeValue )
        {
            case 0xB0:
                strcpy( StartCodeType, "Sequence_Header" );
                break;
            case 0xB2:
                strcpy( StartCodeType, "UserData" );
                break;
            case 0xB3:
                strcpy( StartCodeType, "I_Picture_Header" );
                break;
            case 0xB6:
                strcpy( StartCodeType, "PB_Picture_Header" );
                break;
            case 0xB5:
                strcpy( StartCodeType, "ExtensionData" );
                break;
            default:
                break;
        }

        if ( len == 0 )
        {
#if SYNTAX_REPORT
            if ( StartCodeValue != 0xB3 || StartCodeValue != 0xB6 )
                fprintf( p_sreport, "\n**********************************************\n" );
            fprintf( p_sreport, "No Stuffing Bit At The End Of %s!\n", StartCodeType );
#endif
            //fprintf(p_sreport,"StartCode: 0x%X\n\n", StartCodeValue);
            CSyntax = 0;
            return 0;
        }
        stuffing_bit_num = len % 8;
        stuffing_bit_num = stuffing_bit_num == 0 ? 8 : stuffing_bit_num;
        stuffing_bit_pattern = u_v( stuffing_bit_num, "stuffing pattern" );
        if ( stuffing_bit_pattern == ( 1 << ( stuffing_bit_num - 1 ) ) )
        {
            if ( len == stuffing_bit_num )
                return 1;
            else
            {
                stuffing_byte_len = len - stuffing_bit_num;
                if ( stuffing_byte_len <= 32 )
                {
                    stuffing_byte_pattern = get_uv( stuffing_byte_len, "stuffing_byte" );
                    stuffing_byte_value = stuffing_byte_pattern;
                    is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? 1 : 0;
                }
                else
                {
                    while ( stuffing_byte_len > 32 )
                    {
                        stuffing_byte_pattern = get_uv( 32, "stuffing_byte" );
                        is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? is_sutffing_byte_pattern : 0;
                        stuffing_byte_value += stuffing_byte_pattern;
                        stuffing_byte_len -= 32;
                    }
                    stuffing_byte_pattern = get_uv( stuffing_byte_len, "stuffing_byte" );
                    is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? is_sutffing_byte_pattern : 0;
                    stuffing_byte_value += stuffing_byte_pattern;
                }
                if ( is_sutffing_byte_pattern == 0 )
                {
#if SYNTAX_REPORT
                    if ( StartCodeValue != 0xB3 || StartCodeValue != 0xB6 )
                        fprintf( p_sreport, "\n**********************************************\n" );
                    fprintf( p_sreport, "Wrong Stuffing Byte Pattern At The End Of %s!\n", StartCodeType );
#endif
                    //fprintf(p_sreport,"StartCode: 0x%X\n", StartCodeValue);
                    //if(len-stuffing_bit_num < 16777215)
                    //  fprintf(p_sreport,"Wrong Stuffing Pattern: 0x%X\n\n", stuffing_byte_value);
                    CSyntax = 0;
                    return 0;
                }
                else
                    return 1;
            }
        }
        else
        {
#if SYNTAX_REPORT
            if ( StartCodeValue != 0xB3 || StartCodeValue != 0xB6 )
                fprintf( p_sreport, "\n**********************************************\n" );
            fprintf( p_sreport, "Wrong Stuffing Pattern At The End Of %s!\n", StartCodeType );
            //fprintf(p_sreport,"StartCode: 0x%X\n", StartCodeValue);
            fprintf( p_sreport, "Wrong Stuffing Pattern (%d Stuffing Bits): 0x%X\n\n", stuffing_bit_num, stuffing_bit_pattern );
#endif
            CSyntax = 0;
            if ( len == stuffing_bit_num )
                return 0;
            else
            {
                //stuffing_byte_pattern = get_uv(len-stuffing_bit_num, "stuffing_byte");
                stuffing_byte_len = len - stuffing_bit_num;
                if ( stuffing_byte_len <= 32 )
                {
                    stuffing_byte_pattern = get_uv( stuffing_byte_len, "stuffing_byte" );
                    stuffing_byte_value = stuffing_byte_pattern;
                    is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? 1 : 0;
                }
                else
                {
                    while ( stuffing_byte_len > 32 )
                    {
                        stuffing_byte_pattern = get_uv( 32, "stuffing_byte" );
                        is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? is_sutffing_byte_pattern : 0;
                        stuffing_byte_value += stuffing_byte_pattern;
                        stuffing_byte_len -= 32;
                    }
                    stuffing_byte_pattern = get_uv( stuffing_byte_len, "stuffing_byte" );
                    is_sutffing_byte_pattern = stuffing_byte_pattern == 0 ? is_sutffing_byte_pattern : 0;
                    stuffing_byte_value += stuffing_byte_pattern;
                }
                if ( is_sutffing_byte_pattern == 0 )
                {
#if SYNTAX_REPORT
                    if ( StartCodeValue != 0xB3 || StartCodeValue != 0xB6 )
                        fprintf( p_sreport, "\n**********************************************\n" );
                    fprintf( p_sreport, "Wrong Stuffing Byte Pattern At The End Of %s!\n", StartCodeType );
#endif
                    //fprintf(p_sreport,"StartCode: 0x%X\n", StartCodeValue);
                    //if(len-stuffing_bit_num < 16777215)
                    //  fprintf(p_sreport,"Wrong Stuffing Pattern: 0x%X\n\n", stuffing_byte_value);
                    CSyntax = 0;
                    return 0;
                }
                else
                    return 0;
            }
        }
    }
}
